﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace AnnaLiese
{
    
    public class Matrix2D
    {
        private double[,] matrix;


        public static Matrix2D Identity
        {
            get
            {
                return new Matrix2D(new double[,]{
                {1,0,0},
                {0,1,0},
                {0,0,1}});
            }
        }

        public double[,] Matrix
        {
            get
            {
                return matrix;
            }
            set
            {
                matrix = value;
            }
        }

        public Matrix2D(double[,] mat)
        {
            Matrix = mat;
        }

        public Matrix2D Clone()
        {
            return new Matrix2D(new double[,]{
                {this.Matrix[0,0], this.Matrix[0,1], this.Matrix[0,2]},
                {this.Matrix[1,0], this.Matrix[1,1], this.Matrix[1,2]},
                {this.Matrix[2,0], this.Matrix[2,1], this.Matrix[2,2]}
            });
        }

        public Matrix2D()
        {
            Matrix = new double[3, 3];
        }

        public Matrix2D Invert()
        {
            double det =
                (Matrix[0, 0] * Matrix[1, 1] * Matrix[2, 2]) +
                (Matrix[0, 1] * Matrix[1, 2] * Matrix[2, 0]) +
                (Matrix[0, 2] * Matrix[1, 0] * Matrix[2, 1]) -

                (Matrix[0, 2] * Matrix[1, 1] * Matrix[2, 0]) -
                (Matrix[0, 1] * Matrix[1, 0] * Matrix[2, 2]) -
                (Matrix[0, 0] * Matrix[1, 2] * Matrix[2, 1]);

            Matrix2D adj = new Matrix2D(new double[,]{
                {(Matrix[1,1] * Matrix[2,2]) - (Matrix[1,2] * Matrix[2,1]), (Matrix[0,2] * Matrix[2,1]) - (Matrix[0,1] * Matrix[2,2]), (Matrix[0,1] * Matrix[1,2]) - (Matrix[0,2] * Matrix[1,1])},
                {(Matrix[1,2] * Matrix[2,0]) - (Matrix[1,0] * Matrix[2,2]), (Matrix[0,0] * Matrix[2,2]) - (Matrix[0,2] * Matrix[2,0]), (Matrix[0,2] * Matrix[1,0]) - (Matrix[0,0] * Matrix[1,2])},
                {(Matrix[1,0] * Matrix[2,1]) - (Matrix[1,1] * Matrix[2,0]), (Matrix[0,1] * Matrix[2,0]) - (Matrix[0,0] * Matrix[2,1]), (Matrix[0,0] * Matrix[1,1]) - (Matrix[0,1] * Matrix[1,0])}
            });

            return (1.0 / det) * adj;
        }


        public static Vector2D operator * (Matrix2D mat, Vector2D vector)
        {
            double xTmp = 0, yTmp = 0, zTmp = 0;
            xTmp = (mat.Matrix[0, 0] * vector.X) + (mat.Matrix[0, 1] * vector.Y) + (mat.Matrix[0, 2]);
            yTmp = (mat.Matrix[1, 0] * vector.X) + (mat.Matrix[1, 1] * vector.Y) + (mat.Matrix[1, 2]);
            zTmp = (mat.Matrix[2, 0] * vector.X) + (mat.Matrix[2, 1] * vector.Y) + (mat.Matrix[2, 2]);
            if (zTmp != 1)
            {
                xTmp /= zTmp;
                yTmp /= zTmp;
            }
            return new Vector2D(xTmp, yTmp);
        }

        public static Vector2D operator * (Vector2D vector, Matrix2D mat)
        {
            double xTmp = 0, yTmp = 0, zTmp = 0;
            xTmp = (mat.Matrix[0, 0] * vector.X) + (mat.Matrix[0, 1] * vector.Y) + (mat.Matrix[0, 2]);
            yTmp = (mat.Matrix[1, 0] * vector.X) + (mat.Matrix[1, 1] * vector.Y) + (mat.Matrix[1, 2]);
            zTmp = (mat.Matrix[2, 0] * vector.X) + (mat.Matrix[2, 1] * vector.Y) + (mat.Matrix[2, 2]);
            if (zTmp != 1)
            {
                xTmp /= zTmp;
                yTmp /= zTmp;
            }
            return new Vector2D(xTmp, yTmp);
        }

        public static Matrix2D operator * (Matrix2D mat, double scalar)
        {
            return new Matrix2D(new double[,]{
                {mat.Matrix[0,0] * scalar, mat.Matrix[0,1] * scalar, mat.Matrix[0,2] * scalar},
                {mat.Matrix[1,0] * scalar, mat.Matrix[1,1] * scalar, mat.Matrix[1,2] * scalar},
                {mat.Matrix[2,0] * scalar, mat.Matrix[2,1] * scalar, mat.Matrix[2,2] * scalar}
            });
        }

        public static Matrix2D operator * (double scalar, Matrix2D mat)
        {
            return new Matrix2D(new double[,]{
                {mat.Matrix[0,0] * scalar, mat.Matrix[0,1] * scalar, mat.Matrix[0,2] * scalar},
                {mat.Matrix[1,0] * scalar, mat.Matrix[1,1] * scalar, mat.Matrix[1,2] * scalar},
                {mat.Matrix[2,0] * scalar, mat.Matrix[2,1] * scalar, mat.Matrix[2,2] * scalar}
            });
        }

        public static Matrix2D operator * (Matrix2D mat1, Matrix2D mat2)
        {
            return new Matrix2D(new double[,]{
                {(mat1.Matrix[0,0] * mat2.Matrix[0,0]) + (mat1.Matrix[0,1] * mat2.Matrix[1,0]) + (mat1.Matrix[0,2] * mat2.Matrix[2,0]),      (mat1.Matrix[0,0] * mat2.Matrix[0,1]) + (mat1.Matrix[0,1] * mat2.Matrix[1,1]) + (mat1.Matrix[0,2] * mat2.Matrix[2,1]),      (mat1.Matrix[0,0] * mat2.Matrix[0,2]) + (mat1.Matrix[0,1] * mat2.Matrix[1,2]) + (mat1.Matrix[0,2] * mat2.Matrix[2,2])},
                {(mat1.Matrix[1,0] * mat2.Matrix[0,0]) + (mat1.Matrix[1,1] * mat2.Matrix[1,0]) + (mat1.Matrix[1,2] * mat2.Matrix[2,0]),      (mat1.Matrix[1,0] * mat2.Matrix[0,1]) + (mat1.Matrix[1,1] * mat2.Matrix[1,1]) + (mat1.Matrix[1,2] * mat2.Matrix[2,1]),      (mat1.Matrix[1,0] * mat2.Matrix[0,2]) + (mat1.Matrix[1,1] * mat2.Matrix[1,2]) + (mat1.Matrix[1,2] * mat2.Matrix[2,2])},
                {(mat1.Matrix[2,0] * mat2.Matrix[0,0]) + (mat1.Matrix[2,1] * mat2.Matrix[1,0]) + (mat1.Matrix[2,2] * mat2.Matrix[2,0]),      (mat1.Matrix[2,0] * mat2.Matrix[0,1]) + (mat1.Matrix[2,1] * mat2.Matrix[1,1]) + (mat1.Matrix[2,2] * mat2.Matrix[2,1]),      (mat1.Matrix[2,0] * mat2.Matrix[0,2]) + (mat1.Matrix[2,1] * mat2.Matrix[1,2]) + (mat1.Matrix[2,2] * mat2.Matrix[2,2])}
            });
        }
    }


    public class Vector2D
    {
        private double x;
        private double y;


        public double X 
        {
            get
            {
                return x;
            }
            set
            {
                x = value;
            }
        }

        public double Y
        {
            get
            {
                return y;
            }
            set
            {
                y = value;
            }
        }

        public Vector2D(double xVal, double yVal)
        {
            X = xVal;
            Y = yVal;
        }

        public Vector2D()
        {
            X = 1;
            Y = 1;
        }

        public double Sqrt()
        {
            return (Math.Sqrt((X * X) + (Y * Y)));
        }

        public static implicit operator Point(Vector2D v)
        {
            return new Point(Convert.ToInt32(v.X), Convert.ToInt32(v.Y));
        }

        public static implicit operator PointF(Vector2D v)
        {
            return new PointF((float) v.X, (float) v.Y);
        }

        public static Vector2D operator *(Vector2D pt, double val)
        {
            return new Vector2D(pt.X * val, pt.Y * val);
        }

        public static Vector2D operator *(double val, Vector2D pt)
        {
            return new Vector2D(pt.X * val, pt.Y * val);
        }

        public static Vector2D operator *(Vector2D v1, Vector2D v2)
        {
            return new Vector2D(v1.X * v2.X, v1.Y * v2.Y);
        }
        public static bool operator ==(Vector2D pt1, Vector2D pt2)
        {
            return (pt1.X == pt2.X && pt1.Y == pt2.Y);
        }

        public static Vector2D operator -(Vector2D pt1, Vector2D pt2)
        {
            return new Vector2D(pt1.X - pt2.X, pt1.Y - pt2.Y);
        }

        public static implicit operator Vector2D(Point pt)
        {
            return new Vector2D(pt.X, pt.Y);
        }


        public static bool operator !=(Vector2D pt1, Vector2D pt2)
        {
            return (pt1.X != pt2.X || pt1.Y != pt2.Y);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }
        
    }

}
